package com.xy6.jvm.io;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

/**
 * 字节流操作类和字符流操作类组成了Java IO体系.
 * <pre>
 * 整个Java IO体系都是基于字节流(InputStream/OutputStream) 和 字符流(Reader/Writer)。
 * 作为基类，根据不同的数据载体或功能派生出来的。
 * <p>
 * BufferedReader/BufferedWriter，BufferedInputStream/BufferedOutputStream ， 
 * 		缓冲流用来包装字节流或者字符流，提升IO性能，BufferedReader还可以方便地读取一行，简化编程。
 * FileInputStream/FileOutputStream 需要逐个字节处理原始二进制流的时候使用，效率低下
 * FileReader/FileWriter 需要组个字符处理的时候使用
 * StringReader/StringWriter 需要处理字符串的时候，可以将字符串保存为字符数组
 * PrintStream/PrintWriter 用来包装FileOutputStream 对象，方便直接将String字符串写入文件
 * Scanner　用来包装System.in流，很方便地将输入的String字符串转换成需要的数据类型
 * InputStreamReader/OutputStreamReader ,  字节和字符的转换桥梁，在网络通信或者处理键盘输入的时候用
 * </pre>
 * 
 * @author zhang
 * @since 2018-04-21
 */
public class TestIO {

	public static void FileInputStreamTest() throws IOException {
		FileInputStream fis = new FileInputStream("D:\\音乐\\天空之城.txt");
		byte[] buf = new byte[1024];
		int hasRead = 0;
		
		// read()返回的是单个字节数据（字节数据可以直接转成int类型）
		// 但是read(buf)返回的是读取到的字节数，真正的数据保存在buf中
		while((hasRead = fis.read(buf)) > 0){
			// 每次最多将1024个字节转换成字符串
			// 循环次数=文件字符数/buf长度
			System.out.println(new String(buf, 0, hasRead));
			
			// 将字节强制转换成字符后逐个输出，能实现和上面一样的效果。中文输出乱码
			for(byte b:buf){
				char ch = (char)b;
				if(ch != '\r'){
					System.out.print(ch);
				}
			}
		}
		// 在finally里close更安全
		fis.close();
	}
	
	public static void FileReaderTest(){
		FileReader fr = null;
		try{
			fr = new FileReader("D:\\音乐\\天空之城.txt");
			char[] buf = new char[32];
			int hasRead = 0;
			while((hasRead = fr.read(buf)) > 0){
				// 如果buf的长度大于文件每行的长度，就可以完整输出每行，否则会断行
				// 循环次数=文件字符数/buf长度
				System.out.println(new String(buf, 0, hasRead));
				System.out.println(buf);
			}
		} catch(IOException ex){
			ex.printStackTrace();
		} finally {
			if(null != fr){
				try {
					fr.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
	
	public static void FileOutputStreamTest() {
		FileInputStream fis = null;
		FileOutputStream fos = null;
		try{
			// 在try()中打开文件会在结尾自动关闭
			fis = new FileInputStream("D:\\音乐\\天空之城.txt");
			fos = new FileOutputStream("D:\\音乐\\天空之城2.txt");
			byte[] buf = new byte[4];
			int hasRead = 0;
			while((hasRead = fis.read(buf)) > 0){
				// 每读取一次就写一次，读多少写多少
				fos.write(buf, 0, hasRead);
			}
			System.out.println("write done");
		} catch(IOException e){
			e.printStackTrace();
		} finally {
			if(null != fis){
				try {
					fis.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if(null != fos){
				try {
					fos.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
	
	public static void FileWriterTest() {
		try(FileWriter fw = new FileWriter("D:\\音乐\\天空之城3.txt")){
			fw.write("天王盖地虎\r\n");
			fw.write("宝塔镇河妖\r\n");
		} catch(IOException e){
			e.printStackTrace();
		}
	}
	
	public static void main(String[] args) throws IOException {
		FileInputStreamTest();
		FileReaderTest();
		FileOutputStreamTest();
		FileWriterTest();
	}

}
